import errMagFun from "./errMsg";
import { clearMethodsFun_Type, rstoreAnyType, rBusProtoType } from "../types";

const changeStateFun =
  (_this: rstoreAnyType | rBusProtoType) =>
  (str: string, value?: Array<any>) => {
    if (!str || (_this.listState && !_this.listState[str]))
      return errMagFun("loaded", str);
    try {
      const sumValue: any[] | undefined = value ? value : [];
      return _this.listState[str](...sumValue);
    } catch {}
  };
const pushStateFun =
  (_this: rstoreAnyType | rBusProtoType) => (str: string, fun: Function) => {
    if (_this.listState && !_this.listState[str]) {
      _this.listState[str] = fun;
    }
  };
const asyncChangeStateFun =
  (_this: rstoreAnyType | rBusProtoType) =>
  async (str: string, value?: Array<any>) => {
    const requires = _this.function_that_requires_asynchronous_processing;
    if (requires && !requires[str]) {
      let _resolve: typeof requires[string]["_resolve"] = (value: any) => {
        return;
      };
      const _promise = new Promise((resolve) => {
        _resolve = resolve;
      });
      requires[str] = {
        _resolve,
        _promise,
        _isAsync: true,
      };
    }
    if (requires && requires[str]) {
      const sumValue: any[] | undefined = value ? value : [];
      const result = await requires[str]._promise;
      return result(...sumValue);
    }
  };

const asyncPushStateFun =
  (_this: rstoreAnyType | rBusProtoType) => (str: string, fun: Function) => {
    const requires = _this.function_that_requires_asynchronous_processing;
    if (requires && requires[str] && requires[str]._isAsync) {
      requires[str]._resolve(fun);
    } else {
      if (requires) {
        requires[str] = {
          _promise: fun,
          _resolve: (fun: any) => {
            return fun;
          },
          _isAsync: false,
        };
      }
    }
  };

const clearMethodsFun =
  (_this: rstoreAnyType | rBusProtoType) =>
  (methodKeys: Array<string>, isAsync: boolean) => {
    const methods: clearMethodsFun_Type = isAsync
      ? _this.function_that_requires_asynchronous_processing
      : _this.listState;
    if (methods) {
      const methodsKeys = Object.keys(methods);
      methodKeys.forEach((item) => {
        if (methodsKeys.indexOf(item) !== -1) delete methods[item];
      });
    }
  };
const creatPoxyListState = () => {
  return new Proxy(
    {},
    {
      get(obj: any, key: string): any {
        return obj[key];
      },
      set(obj: any, prop: string, value: any) {
        if (obj[prop]) {
          errMagFun("repetition", prop);
        } else {
          obj[prop] = value;
        }
        return true;
      },
      deleteProperty(obj: any, prop: string) {
        return delete obj[prop];
      },
    }
  );
};

export default (_this: rstoreAnyType | rBusProtoType) => {
  _this.function_that_requires_asynchronous_processing = {};
  _this.listState = creatPoxyListState();
  _this.clearMethods = clearMethodsFun(_this);
  _this.pushState = pushStateFun(_this);
  _this.changeState = changeStateFun(_this);
  _this.asyncPushState = asyncPushStateFun(_this);
  _this.asyncChangeState = asyncChangeStateFun(_this);
};
